using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace Super
{
	/***********************************�Զ�����������*******************************/
	[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
	public class ButtonAttribute : PropertyAttribute
	{
		public string methodName;
		public float btnWidth;

		public ButtonAttribute(string methodName, float btnWidth = 100f)
		{
			this.methodName = methodName;
			this.btnWidth = btnWidth;
		}
	}

	/// <summary>
	/// ����Ļ�����Ϣ�ṹ��
	/// </summary>
	public class ExcelTableInfo
	{
		public List<string> keys = new List<string>();          //���е�key���ֶ�
		public List<string> keyTypes = new List<string>();      //����key������
		public string[] remarks;								//���еı�ע
		public string[] fieldNames;                             //���е��ֶ���
		public string[] fieldTypes;                             //���е��ֶ�����
		public int fieldNum;                                    //�ֶ�����
		public string nodeName;									//�������͵�����
		public string tableName;                                //SO�������
		public string tablePath;								//�������SO��Ĵ��·��
		public bool hasKey;                                     //��������
		public string[][] data;                                 //�������������
		public int row;                                         //��������
		public int col;                                         //��������
		public int ignoreRow;                                   //��������
		public int ignoreCol;                                   //��������
		public bool hasLang;                                    //���ж�����
		public List<string> langFieldNames = new List<string>(); //�������ֶ���
		public List<int> langFieldIndexs = new List<int>();		//����������
	}

	/// <summary>
	/// Excel�����Ļ���������Ϣ
	/// </summary>
	public class ExcelTableBase : ScriptableObject
	{
		public string[] fieldNames;
		public string[] fieldTypes;
		public string[] keys;
		public string[] keyTypes;
	}

	/// <summary>
	/// Excel����ÿ�����ݵĻ���
	/// </summary>
	public class ExcelTableNodeBase
	{
		[HideInInspector]
		public string[] rowData;
		public virtual void SetValue(string[] rowData)
		{
			this.rowData = rowData;
		}

		public virtual void ValueBackFill()
		{

		}
	}

	/// <summary>
	/// �������ڵ�
	/// </summary>
	/// <typeparam name="T"></typeparam>
	public class BinaryTreeNode<T>
	{
		public T value;
		public int height;
		public BinaryTreeNode<T> left;
		public BinaryTreeNode<T> right;
		public BinaryTreeNode<T> parent;


		public BinaryTreeNode(T value, int height = 1)
		{
			this.value = value;
			this.height = height;
		}
	}

	/// <summary>
	/// ������ڵ�
	/// </summary>
	/// <typeparam name="T"></typeparam>
	public class MultiTreeNode<T> where T : IMultiTreeValue<T>
	{
		public T value;
		public int height;
		public List<object> keys = new List<object>();

		//�ֵ䲻�����л����棬�����л����ֵ䱣���ڴ˱����У�֮���ô˱����ָ����ݣ�
		public string dictSerializeJson = "";
		private Dictionary<object, MultiTreeNode<T>> map = new Dictionary<object, MultiTreeNode<T>>();
		public Dictionary<object, MultiTreeNode<T>> Map
		{
			get
			{
				if (map == null)
				{
					if (!String.IsNullOrEmpty(dictSerializeJson))
					{
						map = JsonConvert.DeserializeObject<Dictionary<object, MultiTreeNode<T>>>(dictSerializeJson);
					}
					if (map == null)
					{
						map = new Dictionary<object, MultiTreeNode<T>>();
					}
				}
				return map;
			}
		}

		public MultiTreeNode(int height = 1)
		{
			this.height = height;
		}

		public MultiTreeNode(T value, int height = 1)
		{
			this.value = value;
			this.height = height;
		}
	}

	/// <summary>
	/// ʱ��ڵ�
	/// </summary>
	public class TimerNode : IPriority<TimerNode>
	{
		
		public float endTime;
		public Action<TimerNode> endCallBack;

		public float intervalTime;
		public float nextIntervalEndTime;
		public Action<TimerNode> intervalCallBack;

		public float originLeftTime;
		public float LeftTime => endTime - Time.time;

		public TimerNode(float leftTime, Action<TimerNode> endCallBack)
		{
			originLeftTime = leftTime;
			this.endTime = Time.time + leftTime;
			this.endCallBack = endCallBack;
		}

		public TimerNode(float leftTime, float intervalTime, Action<TimerNode> intervalCallBack)
		{
			originLeftTime = leftTime;
			this.endTime = Time.time + leftTime;
			this.endCallBack = intervalCallBack;
			this.intervalTime = intervalTime;
			this.intervalCallBack = intervalCallBack;
			UpdateIntervalEndTime();
		}

		public TimerNode(float leftTime, float intervalTime, Action<TimerNode> intervalCallBack, Action<TimerNode> endCallBack)
		{
			originLeftTime = leftTime;
			this.endTime = Time.time + leftTime;
			this.endCallBack = endCallBack;
			this.intervalTime = intervalTime;
			this.intervalCallBack = intervalCallBack;
			UpdateIntervalEndTime();
		}

		public void ResetEndTime()
		{
			this.endTime = Time.time + originLeftTime;
		}

		public void UpdateIntervalEndTime()
		{
			nextIntervalEndTime = Time.time + intervalTime;
		}

		public bool Priority(TimerNode other)
		{
			return GetNextCallTime() < other.GetNextCallTime();
		}
		private float GetNextCallTime()
		{
			if (intervalTime == 0)
				return endTime;
			return Mathf.Min(nextIntervalEndTime, endTime);
		}
	}

	/// <summary>
	/// FrameworkSettings�����ýڵ�����
	/// </summary>
	[Serializable]
	public class FWSettingNode
	{
		public string key;              //key
		public bool isActive = true;    //�Ƿ񼤻�
		public string note;             //��ע��Ϣ
		public bool showNotes;          //�Ƿ���ʾ��ע
		public int numInt;              //����
		public float numFloat;          //��������
		public string str;              //�ַ���
		public FWSettingNode(string key)
		{
			this.key = key;
		}
	}

	/// <summary>
	/// FrameworkSettings��ѡ��ڵ�����
	/// </summary>
	[Serializable]
	public class FWOptionNode
	{
		public string key;              //key
		public string name;             //����
		public FWSetShowType showType;		//��ʾ����
		public FWOptionNode(string key, string name, FWSetShowType showType)
		{
			this.key = key;
			this.name = name;
			this.showType = showType;
		}
	}

	/// <summary>
	/// �¼�����ϵͳ��Ҫ�����ݽӿ�
	/// �����Ƴ��������
	/// </summary>
	public struct GameEventNode
	{
		public Type GE_Type;        //�¼�����
		public int priority;        //���ȼ�
	}

	/// <summary>
	/// ·�ɽڵ㰸��
	/// MultiTree<RouteNodeSample>·�ɱ�
	/// </summary>
	public class RouteNodeValueSample : IMultiTreeValue<RouteNodeValueSample>
	{
		public string name;
		public List<object> keys = new List<object>();

		public RouteNodeValueSample(string name, List<object> ints)
		{
			this.name = name;
			this.keys = ints;
		}

		/// <summary>
		/// ��ȡ�ڵ�keys��this.keysֵ��ȵ���������ǰ�������αȽϣ�
		/// </summary>
		/// <param name="root"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		public int GetSameKeyNum(MultiTreeNode<RouteNodeValueSample> root, RouteNodeValueSample value)
		{
			int index = 0;
			for (int i = 0; i < root.keys.Count; i++)
			{
				if (!root.keys[i].Equals(keys[i]))
					break;
				index++;
			}

			return index;
		}

		/// <summary>
		/// �����Ƿ�λ�ڵ�ǰ�ڵ�
		/// </summary>
		/// <param name="root"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		public bool CheckIfCurrentNode(MultiTreeNode<RouteNodeValueSample> root, RouteNodeValueSample value)
		{
			int num = GetSameKeyNum(root, value);
			return num >= keys.Count;
		}

		/// <summary>
		/// ��ȡ��һ·�ɵ�key
		/// ��ͬ��key���� ��һ��������㿪ʼ ��һ
		/// </summary>
		/// <param name="root"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		public object GetMapKey(MultiTreeNode<RouteNodeValueSample> root, RouteNodeValueSample value)
		{
			int num = GetSameKeyNum(root, value);
			return keys[num];
		}

		/// <summary>
		/// ���½ڵ���Ϣ
		/// </summary>
		/// <param name="root"></param>
		/// <param name="value"></param>
		public void UpdateNode(MultiTree<RouteNodeValueSample> tree, MultiTreeNode<RouteNodeValueSample> root, RouteNodeValueSample value)
		{
			if (CheckIfCurrentNode(root, value))
			{
				root.value = value;
				root.keys = value.keys;
			}
			else
			{

			}
		}
	}


	/// <summary>
	/// AABB��ײ������
	/// MultiTree<AABBNodeValueSample> AABB��ģ����
	/// </summary>
	public class AABBNodeValueSample : IMultiTreeValue<AABBNodeValueSample>
	{
		public Bounds Bound;
		public GameObject GO;

		public AABBNodeValueSample()
		{

		}
		public AABBNodeValueSample(Bounds bound, GameObject gO)
		{
			Bound = bound;
			GO = gO;
		}

		/// <summary>
		/// Ѱ���뵱ǰֵ��������Ľڵ�
		/// </summary>
		/// <param name="root"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		public MultiTreeNode<AABBNodeValueSample> FindMinDis(MultiTreeNode<AABBNodeValueSample> root, AABBNodeValueSample value)
		{
			float minDic = 0, dis = 0;
			object minKey = null;
			foreach (var item in root.Map)
			{
				dis = value.Bound.SqrDistance(item.Value.value.Bound.center);
				if (dis < minDic || minKey == null)
				{
					minDic = dis;
					minKey = item.Key;
				}
			}
			return root.Map[minKey];
		}

		/// <summary>
		/// ������λ���Ƿ��ǵ�ǰ�ڵ�
		/// </summary>
		/// <param name="root"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		public bool CheckIfCurrentNode(MultiTreeNode<AABBNodeValueSample> root, AABBNodeValueSample value)
		{
			return root.value == null;
		}

		/// <summary>
		/// ��ȡӳ���key
		/// </summary>
		/// <param name="root"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		public object GetMapKey(MultiTreeNode<AABBNodeValueSample> root, AABBNodeValueSample value)
		{
			if (root.Map.Count >= 4)
			{
				MultiTreeNode<AABBNodeValueSample> minDisNode = FindMinDis(root, value);
				return minDisNode.keys.Last();
			}
			else
			{
				return root.Map.Count;
			}
		}

		/// <summary>
		/// ���µ�ǰ�ڵ�
		/// </summary>
		/// <param name="tree"></param>
		/// <param name="root"></param>
		/// <param name="value"></param>
		public void UpdateNode(MultiTree<AABBNodeValueSample> tree, MultiTreeNode<AABBNodeValueSample> root, AABBNodeValueSample value)
		{
			bool isLeaf = root.Map.Count == 0;
			if (isLeaf)
			{
				root.value = value;
			}
			else
			{
				if (root.value.GO != null)
				{
					AABBNodeValueSample nodevalue = new AABBNodeValueSample(root.value.Bound, root.value.GO);
					root.value.GO = null;
					tree.Insert(nodevalue);
				}
				foreach (var item in root.Map)
				{
					root.value.Bound.Encapsulate(item.Value.value.Bound);
				}
			}
		}
	}

	/// <summary>
	/// Excel�����¼���ݽڵ�
	/// </summary>
	[Serializable]
	public class ExcelNoteNode
	{
		public string excelPath;
		public List<string> SOPaths = new List<string>();       //SriptObject�ı���·��
		public List<string> NodeNames = new List<string>();     //����ڵ�����
		public List<string> TableNames = new List<string>();    //��������
		public List<string> TablePaths = new List<string>();    //�����ౣ��·�����������ļ���������ڵ㡢�����ࣩ

		public ExcelNoteNode(string excelPath)
		{
			this.excelPath = excelPath;
		}
	}

	[Serializable]
	public class LangFileInfo
	{
		public string name;
		public bool isCustom;
		public string absolutePath;
		public string AName;
		private LangDataInfo data;
		public LangDataInfo Data
		{
			get
			{
				if (data == null)
				{
					if (isCustom)
					{
						data = LangUtil.GetDataInfoByPath(absolutePath);
					}
					else
					{
						data = LangUtil.GetDataInfoByAA(AName);
					}
				}
				return data;
			}

		}
	}

	public class LangDataInfo
	{
		public HashSet<string> keys = new HashSet<string>();
		public Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();
	}

	public class CombBtnRunInfo
	{
		public bool isRun1 = false;		//����һ�׶�
		public bool isRun2 = false;     //���ܶ��׶�
		public TimerNode timerNode;
	}

	public class FunBtnTwoInfo
	{
		public bool isPressed = false;
		public float holdTime = 0;
	}
	
	public class MouseMoveInfo
	{
		public Vector2 curPos = Vector2.zero;
		public Vector2 prePos = Vector2.zero;
		public Vector2 offsetPos = Vector2.zero;
		public bool isMoving = false;
	}	
}
